package com.wencai.test;

import com.wencai.bean.*;
import com.alibaba.excel.util.StringUtils;
import com.wencai.daily.utils.ReadUtils;
import com.wencai.util.*;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 比较好的策略:
 * 涨停长度:
 * 5
 * 权重: 5/5,倍率0.5, 9/1, 倍率1.5
 * <p>
 * 最高倍率:
 *
 * @author wangpan
 * @date 2023/5/10
 */
public class Calculate {
    private static String conceptDir = "D:\\Users\\Administrator\\Desktop\\记录\\概念\\";

    private static String branchDir = "D:\\Users\\Administrator\\Desktop\\记录\\行业\\";

    private static String statisticDir = "D:\\Users\\Administrator\\Desktop\\记录\\";

    private static String allDataPath = "D:\\Users\\Administrator\\Desktop\\记录\\所有日线数据\\";

    // 手续费损耗
    private static double feeLoss = 0.00132;

    private static double START_MONEY = 100000;

    private static int defaultLimitUpLength = 3;
    private static int incrementLimit = 3;
    private static double countMultiply = 1;
    private static List<Integer> list = Arrays.asList(new Integer[]{1, 2, 3, 5, 7, 10});
    private static boolean skipLimitUp = true;
    private static boolean skipFurtherTime = true;

    public static void main(String[] args) throws IOException {
        // new BuyStrategy(-1, BuyStrategyType.SKIP_LIMIT_UP)
        // "1500", "1455"
        BuyStrategy buyStrategy = new BuyStrategy(-1, BuyStrategyType.NORMAL);
        SellStrategy sellStrategy = new SellStrategy(8, -1, SellStrategyType.HIGHER);
        String startTime = "1435";
        String endTime = "1500";
        List<BuyStock> gainList = getGainList(startTime, endTime, Calculate::maxMax, conceptDir, buyStrategy,
                sellStrategy, 10, 0);
        CalculateResult calculateResult = TimeLoopUtils.getCalculateResult(startTime, endTime, gainList);
        System.out.println(calculateResult);
        ExportUtils.exportBuyStock(gainList, BuyStock.class, statisticDir + "买卖细节.xlsx");


//        loop(Calculate::maxMax, buyStrategy, sellStrategy, 10, 0);
    }

    private static void loop(StockChooseFunction stockChooser, BuyStrategy buyStrategy, SellStrategy sellStrategy, int incrementWeight, int limitUpCountWeight) throws IOException {
        List<CalculateResult> resultList = listResult(stockChooser, conceptDir, buyStrategy, sellStrategy, incrementWeight, limitUpCountWeight);
        Double average = resultList.stream().mapToDouble(CalculateResult::getGainRate).average().orElse(0);

        System.out.println("incrementWeight is :" + incrementWeight + ";limitUpCountWeight is:" + limitUpCountWeight);
        System.out.println("average result is :" + average);
//        ExportUtils.exportCalculateResult(resultList, CalculateResult.class, statisticDir + "统计.xlsx");

        resultList.sort(Comparator.comparingDouble(CalculateResult::getGainRate));
        System.out.println("min:");
        resultList.subList(0, 5).forEach(System.out::println);
        Collections.reverse(resultList);
        System.out.println("max:");
        resultList.subList(0, 5).forEach(System.out::println);
    }

    static List<CalculateResult> listResult(StockChooseFunction stockChooser,
                                            String dir, BuyStrategy buyStrategy, SellStrategy sellStrategy, int incrementWeight, int limitUpCountWeight) throws IOException {
        Map<String, List<BuyStock>> buyStockMap = new LinkedHashMap<>();
        File f = new File(dir);
        String[] list = f.list();
        double startMoney = START_MONEY;
        int i = 0;
        for (String child : list) {
            if (!child.matches("\\d+\\.txt")) {
                continue;
            }
            String date = child.replaceAll("(\\d+)\\D+", "$1");
            List<String> dataList = IOUtils.readFromFile(dir + child);
            List<IndexStocks> indexStockList = CombineUtils.convertData(dataList, date);
            Stock indexStock = stockChooser.chooseStock(indexStockList, date, incrementWeight, limitUpCountWeight);
            if (indexStock == null) {
                continue;
            }
            if (StringUtils.isEmpty(indexStock.getName())) {
                continue;
            }
            for (String startTime : TimeLoopUtils.getTimeLoop(10, 30)) {
                for (String endTime : TimeLoopUtils.getTimeLoop(9, 35)) {
                    if (startTime.compareTo(endTime) <= 0 && skipFurtherTime) {
                        continue;
                    }
                    String key = startTime + "_" + endTime;
                    List<BuyStock> buyStockList;
                    if (buyStockMap.containsKey(key)) {
                        buyStockList = buyStockMap.get(key);
                    } else {
                        buyStockList = new ArrayList<>();
                    }

                    // 避免明天无数据报错
                    String currentPrice = PriceFinder.findCurrentPrice(indexStock.getName(), indexStock.getDate(), startTime, PriceAction.FIVE_MINUTES_OPEN, buyStrategy);
                    String nextPrice = PriceFinder.findNextPrice(indexStock.getName(), indexStock.getDate(), endTime, PriceAction.FIVE_MINUTES_CLOSE, sellStrategy);
                    // 计算收益率
                    if (StringUtils.isEmpty(currentPrice) || StringUtils.isEmpty(nextPrice)) {
                        continue;
                    }
                    LimitUpInfo limitUpInfo = PriceFinder.findLimitUpInfo(indexStock.getName(), indexStock.getDate());
                    Double currentPriceDouble = Double.valueOf(currentPrice);
                    Double nextPriceDouble = Double.valueOf(nextPrice);

                    BuyStock buyStock = new BuyStock(indexStock.getName(),
                            indexStock.getDate() + startTime,
                            ExchangeDay.getNextExchangeDay(indexStock.getDate()) + endTime,
                            currentPrice, nextPrice);
                    // 获取收益率
                    if (i != 0) {
                        BuyStock lastBuyStock = buyStockList.get(buyStockList.size() - 1);
                        startMoney = lastBuyStock.getEndMoney();
                    }
                    // 半仓买入而不是全仓买入
                    buyStock.setStartMoney(startMoney);

                    long amount = (long) Math.floor(startMoney / (currentPriceDouble * 100));   // 买入手数
                    buyStock.setBuyMoney(amount * currentPriceDouble * 100);
                    buyStock.setSellMoney(amount * 100 * nextPriceDouble * (1 - feeLoss));
                    buyStock.setEndMoney(buyStock.getSellMoney() + startMoney - buyStock.getBuyMoney());

                    Double gainRate = buyStock.getEndMoney() / buyStock.getStartMoney() - 1;
                    buyStock.setGainRate(gainRate);

                    buyStock.setFee(buyStock.getSellMoney() * feeLoss);
                    buyStock.setGain(buyStock.getEndMoney() - buyStock.getStartMoney());
                    buyStock.setAmount(amount);
                    buyStock.setLastLimitUp(limitUpInfo.getLastLimitUpTime());
                    buyStock.setFirstLimitUp(limitUpInfo.getFirstLimitUpTime());
                    buyStock.setIsLimitUp(limitUpInfo.getIsLimitUp());
                    buyStock.setIsOpen(limitUpInfo.getIsOpen());
                    buyStockList.add(buyStock);

                    if (!buyStockMap.containsKey(key)) {
                        buyStockMap.put(key, buyStockList);
                    }
                }
            }
            i++;
        }

        List<CalculateResult> resultList = new ArrayList<>();
        for (Map.Entry<String, List<BuyStock>> entry : buyStockMap.entrySet()) {
            String[] key = entry.getKey().split("_");
            CalculateResult result = TimeLoopUtils.getCalculateResult(key[0], key[1], entry.getValue());
            resultList.add(result);
        }
        return resultList;
    }


    private static List<BuyStock> getGainList(String startTimePoint, String endTimePoint, StockChooseFunction strategy,
                                              String dir, BuyStrategy buyStrategy, SellStrategy sellStrategy, int incrementWeight, int limitUpCountWeight) throws IOException {
        File f = new File(dir);
        String[] list = f.list();
        List<BuyStock> buyStockList = new ArrayList<>();
        double startMoney = START_MONEY;
        int i = 0;
        for (String child : list) {
            if (child.matches("\\d+\\.txt")) {
                String date = child.replaceAll("(\\d+)\\D+", "$1");
                List<String> dataList = IOUtils.readFromFile(dir + child);
                List<IndexStocks> indexStockList = CombineUtils.convertData(dataList, date);
                Stock indexStock = strategy.chooseStock(indexStockList, date, incrementWeight, limitUpCountWeight);
                if (indexStock == null) {
                    continue;
                }
                if (StringUtils.isEmpty(indexStock.getName())) {
                    continue;
                }
                // 避免明天无数据报错
                String currentPrice = PriceFinder.findCurrentPrice(indexStock.getName(), indexStock.getDate(), startTimePoint, PriceAction.FIVE_MINUTES_OPEN, buyStrategy);
                String nextPrice = PriceFinder.findNextPrice(indexStock.getName(), indexStock.getDate(), endTimePoint, PriceAction.FIVE_MINUTES_OPEN, sellStrategy);
                // 计算收益率
                if (StringUtils.isEmpty(currentPrice) || StringUtils.isEmpty(nextPrice)) {
                    continue;
                }
                LimitUpInfo limitUpInfo = PriceFinder.findLimitUpInfo(indexStock.getName(), indexStock.getDate());
                Double currentPriceDouble = Double.valueOf(currentPrice);
                Double nextPriceDouble = Double.valueOf(nextPrice);

                BuyStock buyStock = new BuyStock(indexStock.getName(),
                        indexStock.getDate() + startTimePoint,
                        ExchangeDay.getNextExchangeDay(indexStock.getDate()) + endTimePoint,
                        currentPrice, nextPrice);
                // 获取收益率
                if (i != 0) {
                    BuyStock lastBuyStock = buyStockList.get(i - 1);
                    startMoney = lastBuyStock.getEndMoney();
                }
                // 半仓买入而不是全仓买入
                buyStock.setStartMoney(startMoney);

                long amount = (long) Math.floor(startMoney / (currentPriceDouble * 100));   // 买入手数
                buyStock.setBuyMoney(amount * currentPriceDouble * 100);
                buyStock.setSellMoney(amount * 100 * nextPriceDouble * (1 - feeLoss));
                buyStock.setEndMoney(buyStock.getSellMoney() + startMoney - buyStock.getBuyMoney());

                Double gainRate = buyStock.getEndMoney() / buyStock.getStartMoney() - 1;
                buyStock.setGainRate(gainRate);

                buyStock.setFee(buyStock.getSellMoney() * feeLoss);
                buyStock.setGain(buyStock.getEndMoney() - buyStock.getStartMoney());
                buyStock.setAmount(amount);
                buyStock.setLastLimitUp(limitUpInfo.getLastLimitUpTime());
                buyStock.setFirstLimitUp(limitUpInfo.getFirstLimitUpTime());
                buyStock.setIsLimitUp(limitUpInfo.getIsLimitUp());
                buyStock.setIsOpen(limitUpInfo.getIsOpen());
                buyStockList.add(buyStock);
                i++;
            }
        }
        return buyStockList;
    }

    private static Stock convertStock(IndexStocks indexStocks) {
        if (indexStocks == null) {
            return null;
        }
        return new Stock(indexStocks.getFirstStockName(), indexStocks.getFirstStockCode(), indexStocks.getFirstStockIncrement(), indexStocks.getDate());
    }

    // 获取板块涨幅最大且个股涨幅最大的第一只票
    public static Stock maxMax(List<IndexStocks> list, String date, int incrementWeight, int limitUpCountWeight) {
        return convertStock(list.stream()
                .max(Comparator.comparingDouble(IndexStocks::getMaxIncrement))
                .orElse(null));
    }


    //TODO
    // 获取百日涨停数最多的股票
    public static Stock stopLimitCountMax(List<IndexStocks> list, String date, int incrementWeight, int limitUpCountWeight) {
        return convertStock(list.stream()
                .max(Comparator.comparingDouble(IndexStocks::getMaxIncrement))
                .orElse(null));
    }

    public static Stock getStockWithWeight(List<IndexStocks> list, String date, int incrementWeight, int limitUpCountWeight) throws IOException {
        List<Stock> stocks = new ArrayList<>();
        for (IndexStocks indexStocks : list) {
            addAllStocks(stocks, indexStocks);
        }
        if (skipLimitUp) {
            // 获取所有票当天的涨幅
            stocks = stocks.stream().filter(item -> {
                try {
                    return ReadUtils.readOneDailyData(allDataPath, item.getCode() + ".txt", date).getPctChg() > 9.5;
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return false;
            }).collect(Collectors.toList());
        }

        if (stocks.isEmpty()) {
            return null;
        }
        double maxValue = -1;
        int i = 0;
        int index = 0;
        for (Stock stock : stocks) {
            double value;
            double increment = Double.valueOf(stock.getIncrement());
            if (limitUpCountWeight == 0) {
                value = increment * incrementWeight;
            } else {
                int count = LimitUpCountUtils.getLimitUpCount(stock.getCode(), stock.getDate(), defaultLimitUpLength);
                value = count * limitUpCountWeight * countMultiply + increment * incrementWeight;
            }

            stock.setValue(value);
            if (value > maxValue) {
                index = i;
                maxValue = value;
            }
            i++;
        }
        return stocks.get(index);
    }

    private static void addAllStocks(List<Stock> stocks, IndexStocks indexStocks) {
        if (indexStocks == null) {
            return;
        }
        if (!StringUtils.isEmpty(indexStocks.getFirstStockName()) && !StringUtils.isEmpty(indexStocks.getFirstStockIncrement())) {
            stocks.add(new Stock(indexStocks.getFirstStockName(), indexStocks.getFirstStockCode(), indexStocks.getFirstStockIncrement(), indexStocks.getDate()));
        }
        if (!StringUtils.isEmpty(indexStocks.getFirstStockName()) && !StringUtils.isEmpty(indexStocks.getFirstStockIncrement())) {
            stocks.add(new Stock(indexStocks.getFirstStockName(), indexStocks.getFirstStockCode(), indexStocks.getFirstStockIncrement(), indexStocks.getDate()));
        }
        if (!StringUtils.isEmpty(indexStocks.getFirstStockName()) && !StringUtils.isEmpty(indexStocks.getFirstStockIncrement())) {
            stocks.add(new Stock(indexStocks.getFirstStockName(), indexStocks.getFirstStockCode(), indexStocks.getFirstStockIncrement(), indexStocks.getDate()));
        }
    }

    // 获取第一个
    public static Stock getFirst(List<IndexStocks> list, String d, int incrementWeight, int limitUpCountWeight) {
        if (list.isEmpty()) {
            return null;
        }
        String firstStockName = list.get(0).getFirstStockName();
        String firstStockIncrement = list.get(0).getFirstStockIncrement();
        String firstStockCode = list.get(0).getFirstStockCode();
        String date = list.get(0).getDate();
        return new Stock(firstStockName, firstStockCode, firstStockIncrement, date);
    }
}
